package middleware

import (
	"context"
	"github.com/gogf/gf/v2/encoding/gjson"
	"github.com/gogf/gf/v2/errors/gcode"
	"github.com/gogf/gf/v2/errors/gerror"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/gogf/gf/v2/net/gtrace"
	"github.com/gogf/gf/v2/os/gctx"
	"github.com/gogf/gf/v2/os/gtime"
	"go.opentelemetry.io/otel/attribute"
	"net/http"
	"zuhao-seucre/internal/common"
	"zuhao-seucre/internal/common/model"
	"zuhao-seucre/internal/service"
	"zuhao-seucre/utility/validate"
)

func init() {
	service.RegisterMiddleware(New())
}

func New() *sMiddleware {
	return &sMiddleware{}
}

type sMiddleware struct{}

// ZuHaoAuthToken 后台鉴权中间件
func (s *sMiddleware) ZuHaoAuthToken(r *ghttp.Request) {
	var (
		ctx  = r.Context()
		path = r.URL.Path
	)
	// 不需要验证登录的路由地址
	if IsExceptLogin(ctx, path) {
		r.Middleware.Next()
		return
	}
	// 将用户信息传递到上下文中
	if err := DeliverUserContext(r); err != nil {
		common.JsonExit(r, gcode.CodeNotAuthorized.Code(), err.Error())
		return
	}

	// 不需要验证权限的路由地址
	if IsExceptAuth(ctx, path) {
		r.Middleware.Next()
		return
	}
	// 验证路由访问权限 todo

	r.Middleware.Next()
}

// ZuHaoCORS allows Cross-origin resource sharing.
func (s *sMiddleware) ZuHaoCORS(r *ghttp.Request) {
	r.Response.CORSDefault()
	r.Middleware.Next()
}

// 初始化请求上下文
func (s *sMiddleware) ZuHaoCtx(r *ghttp.Request) {
	if g.Cfg().MustGet(r.Context(), "jaeger.switch").Bool() {
		ctx, span := gtrace.NewSpan(r.Context(), "middleware.ctx")
		span.SetAttributes(attribute.KeyValue{
			Key:   "traceID",
			Value: attribute.StringValue(gctx.CtxId(ctx)),
		})
		span.End()
		r.SetCtx(ctx)
	}

	data := make(g.Map)

	data["request.body"] = gjson.New(r.GetBodyString())

	service.ContextX().Init(r, &model.Context{
		Data: data,
	})

	if len(r.Cookie.GetSessionId()) == 0 {
		r.Cookie.SetSessionId(gctx.CtxId(r.Context()))
	}

	r.SetCtx(r.GetNeverDoneCtx())
	r.Middleware.Next()
}

// ZuHaoResponse is the default middleware handling handler response object and its error.
func (s *sMiddleware) ZuHaoResponse(r *ghttp.Request) {
	r.Middleware.Next()

	// There's custom buffer content, it then exits current handler.
	if r.Response.BufferLength() > 0 {
		return
	}

	var (
		e    interface{}
		msg  = "success"
		err  = r.GetError()
		res  = r.GetHandlerResponse()
		code = gerror.Code(err)
	)
	if err != nil {
		if code == gcode.CodeNil {
			code = gcode.CodeInternalError
		}
		e = err.Error()
		msg = err.Error()
	} else {
		if r.Response.Status > 0 && r.Response.Status != http.StatusOK {
			msg = http.StatusText(r.Response.Status)
			switch r.Response.Status {
			case http.StatusNotFound:
				code = gcode.CodeNotFound
			case http.StatusForbidden:
				code = gcode.CodeNotAuthorized
			default:
				code = gcode.CodeUnknown
			}
			// It creates e as it can be retrieved by other middlewares.
			err = gerror.NewCode(code, msg)
			r.SetError(err)
		} else {
			code = gcode.New(200, "OK", nil)
		}
	}

	r.Response.WriteJson(model.Response{
		Code:      code.Code(),
		Message:   msg,
		Data:      res,
		Timestamp: gtime.Timestamp(),
		Error:     e,
		TraceID:   gctx.CtxId(r.Context()),
	})
}

// DeliverUserContext 将用户信息传递到上下文中
func DeliverUserContext(r *ghttp.Request) (err error) {
	user, err := service.Token().ParseLoginUser(r)
	if err != nil {
		return
	}
	service.ContextX().SetUser(r.Context(), user)
	return
}

// IsExceptLogin 是否是不需要登录的路由地址
func IsExceptLogin(ctx context.Context, path string) bool {
	conf := service.Config().MustGetTokenConf()
	pathList := conf.ExceptLogin
	for i := 0; i < len(pathList); i++ {
		if validate.InSliceExistStr(pathList[i], path) {
			return true
		}
	}
	return false
}

// IsExceptAuth 是否是不需要验证权限的路由地址
func IsExceptAuth(ctx context.Context, path string) bool {
	conf := service.Config().MustGetTokenConf()
	pathList := conf.ExceptAuth
	for i := 0; i < len(pathList); i++ {
		if validate.InSliceExistStr(pathList[i], path) {
			return true
		}
	}
	return false
}
